package com.jiang.annotation.aop.global_exception_handle;

import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;

import java.io.Serializable;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author Administrator
 * @Date 2023 12 15 10 32
 **/
@Schema(
        title = "统一响应返回实体",
        description = "所有Rest接口统一返回的实体定义",
        example = "new Result<T>().ok().message(\"XXX\")"
)
public class Result<T> implements Serializable {
    private static final long serialVersionUID = 1L;
    @Schema(
            title = "自定义响应编码"
    )
    private int code = 0;
    @Schema(
            title = "响应返回信息"
    )
    private String message;
    @Schema(
            title = "请求路径"
    )
    private String path;
    @Schema(
            title = "响应返回数据"
    )
    private T data;
    @Schema(
            title = "http状态码"
    )
    private int status;
    @Schema(
            title = "响应时间戳",
            pattern = "yyyy-MM-dd HH:mm:ss"
    )
    @JsonFormat(
            pattern = "yyyy-MM-dd HH:mm:ss"
    )
    private Date timestamp = new Date();
    @Schema(
            title = "校验错误信息"
    )
    private final Error error = new Error();

    public Result() {
    }

    public int getCode() {
        return this.code;
    }

    public String getMessage() {
        return this.message;
    }

    public String getPath() {
        return this.path;
    }

    public T getData() {
        return this.data;
    }

    public int getStatus() {
        return this.status;
    }

    public Date getTimestamp() {
        return this.timestamp;
    }

    public Error getError() {
        return this.error;
    }

    /** @deprecated */
    @Deprecated
    public Result<T> ok() {
        this.code = ResultStatus.OK.getCode();
        this.message = ResultStatus.OK.getMessage();
        this.status = 200;
        return this;
    }

    /** @deprecated */
    @Deprecated
    public Result<T> failed() {
        this.code = ResultStatus.FAIL.getCode();
        this.message = ResultStatus.FAIL.getMessage();
        this.status = 500;
        return this;
    }

    public Result<T> code(int code) {
        this.code = code;
        return this;
    }

    public Result<T> message(String message) {
        this.message = message;
        return this;
    }

    public Result<T> data(T data) {
        this.data = data;
        return this;
    }

    public Result<T> path(String path) {
        this.path = path;
        return this;
    }

    public Result<T> type(ResultStatus resultStatus) {
        this.code = resultStatus.getCode();
        this.message = resultStatus.getMessage();
        return this;
    }

    public Result<T> status(int httpStatus) {
        this.status = httpStatus;
        return this;
    }

    public Result<T> stackTrace(StackTraceElement[] stackTrace) {
        this.error.setStackTrace(stackTrace);
        return this;
    }

    public Result<T> detail(String detail) {
        this.error.setDetail(detail);
        return this;
    }

    public Result<T> validation(String message, String code, String field) {
        this.error.setMessage(message);
        this.error.setCode(code);
        this.error.setField(field);
        return this;
    }

    private static <T> Result<T> create(String message, String detail, int code, int status, T data, StackTraceElement[] stackTrace) {
        Result<T> result = new Result();
        if (StringUtils.isNotBlank(message)) {
            result.message(message);
        }

        if (StringUtils.isNotBlank(detail)) {
            result.detail(detail);
        }

        result.code(code);
        result.status(status);
        if (ObjectUtils.isNotEmpty(data)) {
            result.data(data);
        }

        if (ArrayUtils.isNotEmpty(stackTrace)) {
            result.stackTrace(stackTrace);
        }

        return result;
    }

    public static <T> Result<T> success(String message, int code, int status, T data) {
        return create(message, null, code, status, data, null);
    }

    public static <T> Result<T> success(String message, int code, T data) {
        return success(message, code, 200, data);
    }

    public static <T> Result<T> success(ResultStatus resultStatus, T data) {
        return success(resultStatus.getMessage(), resultStatus.getCode(), data);
    }

    public static <T> Result<T> success(String message, T data) {
        return success(message, ResultStatus.OK.getCode(), data);
    }

    public static <T> Result<T> success(String message) {
        return success(message, null);
    }

    public static <T> Result<T> success() {
        return success("操作成功！");
    }

    public static <T> Result<T> content(T data) {
        return success("操作成功！", data);
    }

    public static <T> Result<T> failure(String message, String detail, int code, int status, T data, StackTraceElement[] stackTrace) {
        return create(message, detail, code, status, data, stackTrace);
    }

    public static <T> Result<T> failure(String message, String detail, int code, int status, T data) {
        return failure(message, detail, code, status, data, (StackTraceElement[])null);
    }

    public static <T> Result<T> failure(String message, int code, int status, T data) {
        return failure(message, message, code, status, data);
    }

    public static <T> Result<T> failure(String message, String detail, int code, T data) {
        return failure(message, detail, code, 500, data);
    }

    public static <T> Result<T> failure(String message, int code, T data) {
        return failure(message, message, code, data);
    }

    public static <T> Result<T> failure(ResultStatus resultStatus, T data) {
        return failure(resultStatus.getMessage(), resultStatus.getCode(), data);
    }

    public static <T> Result<T> failure(String message, T data) {
        return failure(message, ResultStatus.FAIL.getCode(), data);
    }

    public static <T> Result<T> failure(String message) {
        return failure(message, null);
    }

    public static <T> Result<T> failure() {
        return failure("操作失败！");
    }

    public Map<String, Object> toModel() {
        Map<String, Object> result = new HashMap(8);
        result.put("code", this.code);
        result.put("message", this.message);
        result.put("path", this.path);
        result.put("data", this.data);
        result.put("status", this.status);
        result.put("timestamp", this.timestamp);
        result.put("error", this.error);
        return result;
    }
}
